/*
 *      This program is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation; either version 2 of the License, or
 *      (at your option) any later version.
 *      
 *      This program is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *      
 *      You should have received a copy of the GNU General Public License
 *      along with this program; if not, write to the Free Software
 *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 *      MA 02110-1301, USA.
 */

#ifndef _GTYPE_H
#define _GTYPE_H

#include <iostream>
#include <vector>
#include <map>
#include <limits>
#include <cstring>

#include "reader.h"
#include "lexical.h"

//! Linearní interpolace nejvyšší možnou rychlostí.
#define TYPE_LINEAR_MOVE		0
//! Linearní interpolace zadanou obráběcí rychlostí.
#define TYPE_LINEAR_CUT			1
//! Kruhová interpolace po směru hodinových ručiček zadanou obráběcí rychlostí.
#define TYPE_ARC_CLOCK 			2
//! Kruhová interpolace proti směru hodinových ručiček zadanou obráběcí rychlostí.
#define TYPE_ARC_COUNTER 		3
//! Přepnutí na absolutní souřadnice.
#define TYPE_COORDINATES_ABS	90
//! Přepnutí na relativní souřadnice.
#define TYPE_COORDINATES_REL	91

//! Zakladní typ instrukce.
/*!
 * Odvozují se od něj další komplexnější typy. Obsahuje jen informaci o 
 * použitém symbolu. Zatím jediný použitý symbol je symbol GO_G.
 *  
*/
class gType{

	private:
		lexical::token::symbols symbol;
	
	public:
		gType(lexical::token::symbols);
		//! Vrací symbol.
		/*!
		* Prozatím, jediný používaný symbol je GO_G. Může obsahovat
		* všechny symboly definované výčtovým typem enum 
		* v lexical::token::symbols
		*/
		virtual lexical::token::symbols getSymbol() const;
		//! Kopíruje objekt.
		/*!
		* Vytváří dynamicky nový objekt pomocí operátoru new, který
		* je kopií původního. Zkopírovaný objekt je potřeba dealokovat.
		* Každá odvozená třída z této třídy, by měla implementovat tuto
		* metodu.
		*/
		virtual gType *copy() const;
		//! Přetížený operátor přiřazení.
		/*!
		* Nutno implementovat i ve třídách odvozených, aby bylo zajištěno
		* že dojde vždy ke skopírování celého objektu.
		*/
		virtual gType &operator=(const gType &);

};

//! Typ linearní interpolace
/*!
 * Obsahuje 3 floaty (souřadnice bodu v prostoru) a typ symbolu.
 * Je používám pro instrukci G0 a G1 a je z něho odvozen typ kruhové
 * interpolace.
*/
class gTypeGo: public gType{

	private:
		unsigned typeValue;
		float xyzCoordinates[3];
		
	public:
		//! Konstrukor typu linearní interpolace.
		/*!
		* \param type Typ symbolu. Každý symbol obsahuje číselnou informaci, která
		* definuje interpolaci, která se má použít.
		* \param x Souřadnice osy x.
		* \param y Souřadnice osy z.
		* \param z Souřadnice osy z.
		*/
		gTypeGo(unsigned, float, float, float);
		
		//! Vrací typ symbolu.
		/*!
		 * Prozatím použité typy jsou v intervalu <0, 3>;
		*/
		unsigned getTypeValue() const;
		//! Vrací souřadnici.
		/*!
		* K souřadnícím objektu zle přistupovat 
		* podobně jako k poli [x, y, z].
		*  \param i Index souřadnice i = 0, 1, 2.
		*/
		virtual float &operator[](unsigned);
		virtual gType *copy() const;
		virtual gType &operator=(const gType &);

};

//! Typ kruhové interpolace.
/*!
 * Obsahuje navíc 3 floaty (souřadnice bodu v prostoru), které určují
 * střed kružnice. Střed kružnice je dán relativně k předchozímu bodu.
 * Používá se pro reprezentaci kruhové výseče G2 a G3.
*/
class gTypeGoCircle: public gTypeGo{

	private:
		float ijkCoordinates[3];
	
	public:
		//! Konstrukor typu kruhová interpolace.
		/*!
		 * [i, j, k] jsou souřadnice středu kruhu. Souřadnice jsou 
		 * relativní k předchozímu bodu. 
		* \param type Typ symbolu.
		* \param x Souřadnice osy x.
		* \param y Souřadnice osy z.
		* \param z Souřadnice osy z.
		* \param i Souřadnice osy i.
		* \param j Souřadnice osy j.
		* \param k Souřadnice osy k.
		* \see class gObject 
		*/
		gTypeGoCircle(unsigned, float, float, float, float, float, float);
		//! Vrací souřadnici.
		/*!
		* K souřadnícím objektu zle přistupovat 
		* podobně jako k poli [x, y, z, i, j, k].
		*  \param i Index souřadnice i = 0, 1, ...,5.
		*/
		virtual float &operator[](unsigned);
		virtual gType *copy() const;
		virtual gType &operator=(const gType &);

};

//! Kontejner pro instrukce.
/*!
 * Představuje obsah bloku mezi tagy (#OBJECT name)...(#!OBJECT name). Obsahuje informace o
 * rychlosti posuvu, počtu otáček, ... před vstupem do bloku, nebo během průchodu blokem. 
 * Instrukce uložené v objektu jsou ukládány ve stejném pořadí, jako bylo jejich pořadí v
 * bloku. Sekvenční přístup z hora dolů.
*/
class gObject: public std::vector<gType *>{

	private:
		static const float GAP = 0.001;
	
		std::string name;
		bool relative, forceRelative;
		float feed, originalFeed;
		int spindle, originalSpindle;
		unsigned long startOffset, length;
		
	public:
                bool alter;

		gObject();
		//! Vytváří hlubukou kopii objektu.
		/*!
		* Jelikož v tento kontejner přechovává jen ukazatele, je třeba 
		* definovat kopírovací konstruktor vytvářející hlubokou kopii.
		* Kopírovací konstruktor dostávající referenci téhož objektu vytváří
		* jen plítkou kopii.
		*/
		gObject(gObject *);
		~gObject();
		
		//! 
		bool isForceRelative() const
			{ return forceRelative; };
		//! 
		void setForceRelative(bool boolean)
			{ forceRelative = boolean; };
		//! 
		void setOriginalFeed(float f)
			{ originalFeed = f; };
		//!
		float getOriginalFeed() const
			{ return originalFeed; };
		//! 
		void setOriginalSpindle(int s)
			{ originalSpindle = s; };
		//!
		int getOriginalSpindle() const
			{ return originalSpindle; };
		
		//! Jestli byly použité relativní souřadnice.
		bool isRelative() const;
		//! Nastavit relativní souřadnice.
		void setRelative(bool);
		//! Vrací rychlost posuvu před vstupem do bloku.
		float getFeed() const;
		//! Nastaví rychlost posuvu před vstupem do bloku.
		void setFeed(float);
		//! Vratí počet otáček vřetena před vstupem do bloku.
		int getSpindle() const;
		//! Nastaví počet otáček vřetena před vstupem do bloku.
		void setSpindle(int);
		//! Nastaví absolutní offset začátku bloku v souboru a počet bytů od začátku bloku.
		/*!
		* Tahle informace slouží hlavně pro účely serializace k sestavení
		* výstupního souboru.
		* \param start Označuje začátek bloku. Představuje absolutní offset souboru,
		* který ukazuje na prvni znak tagu (#OBJECT ....
		* \param len Označuje délku bloku, opět až po poslední znak tagu (#!OBJECT jméno).
		*/
		void setOffsets(unsigned long, unsigned long);
		//! Vrací offset začáteku bloku v souboru.
		unsigned long getStartOffset() const;
		//! Vrací počet znaků od začátku bloku po konec.
		unsigned long getLength() const;
		//! Vrací obdelník v kterém se nachází.
		/*!
		* Zjistí minimalní obdelník, který je potřeba pro vykreslení
		* tohoto bloku.
		* \param rec Pole floatů určující souřadnice obdelníku. Jedná
		* se o pravý horní roh a levý spodní roh obdelníku [x0, y0, x1, y1].
		*/
		float *getRectangle(float *);
		//! Nastaví jméno bloku.
		void setName(std::string &);
		//! Vrací jméno bloku.
		std::string &getName();
		//! Aktualní index (umísťění) objektu v kontejneru.
		/*!
		* \param type Ukazatel na typ, který je pořeba najít.
		* \return V případě nenalezení vrací záporný index.
		*/
		int getIndexByObject(gType *) const;
		//! Obstarává správné skopírování objektu.
		gObject &operator=(const gObject &);
		
		gObject getHight(gTypeGo &);
		
};

//! Kontejner bloků.
/*!
 * Obsahuje jednotlivé bloky, tak jak šly za sebou.
*/
class gObjectContainer: public std::vector<gObject *>{
	
	public:
		gObjectContainer();
		//! Vytváří hlubukou kopii objektu.
		/*!
		* Jelikož v tento kontejner přechovává jen ukazatele, je třeba 
		* definovat kopírovací konstruktor vytvářející hlubokou kopii.
		* Kopírovací konstruktor dostávající referenci téhož objektu vytváří
		* jen plítkou kopii.
		*/
		~gObjectContainer();
		
		gObjectContainer(gObjectContainer *);
		/*!
		* \return Vrací ukazatel na blok příslušného jména, v případě
		* že se jméno neshoduje, vrací NULL.
		*/
		gObject *getObjectByName(std::string &);
		//! Vrací obdelník v kterém se nachází.
		/*!
		* Zjistí minimalní obdelník, který je potřeba pro vykreslení
		* celého kontejneru bloků.
		* \param rec Pole floatů určující souřadnice obdelníku. Jedná
		* se o pravý horní roh a levý spodní roh obdelníku [x0, y0, x1, y1].
		*/
		float *getRectangle(float *);
		//! Aktualní index (umísťění) objektu v kontejneru. 
		/*!
		* \param object Ukazatel na typ, který je pořeba najít.
		* \return V případě nenalezení vrací záporný index
		*/
		int getIndexByObject(gObject *) const;
		//! Obstarává správné skopírování objektu.
		gObjectContainer &operator=(const gObjectContainer &);
		
		gObjectContainer getHight(gTypeGo &);
		
	
};

#endif
